const fs = require('fs')
const path = require('path')
const globby = require('globby')
const log = require('./log')
const packageJson = require('./package.json')

module.exports = class {
  constructor(options) {
    this.options = options
  }
  apply(compiler) {
    if (compiler) {
      if (compiler.hooks) {
        // 推荐写法
        compiler.hooks.afterEmit.tap(packageJson.name, (stats) => {
          this.handle(compiler)
        })
      } else {
        // 兼容webpack3写法
        compiler.plugin('afterEmit', (stats) => {
          this.handle(compiler)
        })
      }
    } else {
      log.red(`[${packageJson.name}] compiler not found`)
    }
  }
  /**
   * 处理
   * @param {Object} compiler
   */
  handle(compiler) {
    // 检验参数配置必填项
    if (!this.checkOptions()) {
      return
    }
    // 预计用于配置项的内容
    // 输出文件位置
    const outputPath = path.resolve(compiler.options.output.path)
    // 获取需要上传的资源文件
    globby(this.options.from).then((files) => {
      // 1 获取文件路径列表
      const filePaths = []
      files.map((item) => {
        filePaths.push(path.normalize(path.resolve(item)))
      })
      
      // 2 获取全部文件中匹配的classname列表
      let replaceList = []
      let replaceStrs = []
      // 2.1 获取所有classname列表
      filePaths.map((item) => {
        var data = fs.readFileSync(item, { encoding: 'utf8' })
        let dataStr = data.toString()
        // 获取当前文件中匹配的classname列表
        var theArr = dataStr.split(this.options.split[0])
        theArr.shift()
        theArr.map((item) => {
          const classStr = item.split(this.options.split[1])[0]
          replaceList.push(...classStr.split(' '))
          replaceStrs.push(classStr)
        })
      })
      // 2.2 过滤列表并排序 倒序（避免相同名字前缀的被替换所以使用倒序 如：'a-b a-b-c' 先替换 a-b-c 再替换 a-b）
      replaceList = [...new Set(replaceList.filter(item => this.options.regex.test(item)))].sort().reverse()
      
      // 3 生成替换的键值对
      const replaceMap = []
      replaceList.map((key, index) => {
        replaceMap.push({
          key: key, // 替换前的className
          str: `${this.numberToLetter(index)}${this.getRandomLetter(2)}-${this.getRandomLetter(3)}` // 生成替换结果
        })
      })
      
      // 4 从文件内容拆分出className数组
      replaceStrs = [...new Set(replaceStrs.filter(item => {
        let isTrue = false
        item.split(' ').map((str) => {
          if (this.options.regex.test(str)) {
            isTrue = true
          }
        })
        return isTrue
      }))]
      
      // 5 替换拆分出来的className数组中匹配项
      const replaceStrsNew = []
      replaceStrs.map((str) => {
        let strTemp = str
        replaceMap.map((item) => {
          strTemp = strTemp.replace(new RegExp(item.key, 'g'), item.str)
        })
        replaceStrsNew.push(strTemp)
      })
      
      // 6 替换并写入文件
      filePaths.map((item) => {
        var data = fs.readFileSync(item, { encoding: 'utf8' })
        let dataStr = data.toString()
        // 替换className
        replaceStrs.map((str, index) => {
          const symbol = this.options.split[1]
          dataStr = dataStr.replace(new RegExp(symbol + str + symbol, 'g'), symbol + replaceStrsNew[index] + symbol)
        })
        // 替换css名称 以.开头.>~ +:,[{结尾
        const tailArr = ['.', '>', '~', ' ', '+', ':', ',', '[', '{']
        replaceMap.map((item) => {
          tailArr.map((tail) => {
            dataStr = dataStr.replace(new RegExp(`.${item.key}\\${tail}`, 'g'), `.${item.str}${tail}`)
          })
        })
        // 写入内容
        fs.writeFile(item, dataStr, (err) => {
          if (err) return err
        })
      })
    }).catch((err) => {
      console.error(err)
    })
  }
  /**
   * 检验参数配置必填项
   */
  checkOptions() {
    // 配置项检验
    if (!this.options.from) {
      log.red(`[${packageJson.name}] 'from' not found in options`)
      return false
    }
    
    if (!this.options.split) {
      log.red(`[${packageJson.name}] 'split' not found in options`)
      return false
    }
    if (!Array.isArray(this.options.split)) {
      log.red(`[${packageJson.name}] 'split' not an array`)
      return false
    }
    if (!this.options.split.length == 2) {
      log.red(`[${packageJson.name}] 'split' length is not 2`)
      return false
    }
    
    if (!this.options.regex) {
      log.red(`[${packageJson.name}] 'regex' not found in options`)
      return false
    }
    if (!Object.prototype.toString.call(this.options.regex) === '[object RegExp]') {
      log.red(`[${packageJson.name}] 'regex' is not a RegExp`)
      return false
    }
    return true
  }
  /**
   * 生成随机字母
   * @param {Object} leng 长度
   */
  getRandomLetter(leng) {
    let str = 'a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z'
	  let arr = str.split(',')
    let rand = ''
    for(var i = 0; i < leng; i++) {
        rand += arr[Math.floor(Math.random() * 26)]
    }
    return rand
  }
  /**
   * 数字转换为数组
   * @param {String} num
   */
  numberToLetter(num) {
    num = num + ''
    let str = 'o,a,b,c,d,e,f,g,h,i'
    let arr = str.split(',')
    let lett = ''
    for(var i = 0; i < num.length; i++) {
      lett += arr[num[i]]
    }
    return lett
  }
}